經過半個月的時間,把上次分享的問題【可撐長時間運作的動態網頁技術?】做個總結。
前文提到,因為網頁天生不是用來擺著長時間運作的。所以它的運作環境,包含瀏覽器、DOM、Javascript 及 Framework,通常開發的模式都是肆無忌憚地 allocate 記憶體來用,而不去考慮記憶體釋放問題。因為網頁的生命期很短,大多只會看幾秒就換頁或關掉了。短到來不及發生記憶體不足的問題。這是前因。
敝人工作上所經手的開發需求,是要以 Web 為操作介面,嵌進 ActiveX player,做長時間的影像監控,並且運用 Comet 技術,與 server 端保持聯繫、取得最新資訊以顯示在頁面上。需求不難做,但是在長時間運作下,瀏覽器會因為記憶體耗光而在短短數小時內就 crash,根本無法做數日、數月的監控。這是後果。
邦友們的建議如下:
手動或自動 refresh 頁面。很抱歉,無效。被佔的記憶體不會釋放,而且客戶也無法接受頁面為什麼要重新整理。
開發 Windows AP 來取代 Web。這是大多數監控廠商的作法,有效,但遠水救不了近火。通常開發 AP 沒半年也要三季,假如又要符合 32bit、64bit、iOS、Android ... 各平台,別說是三天要解決,這可能得先花半年找齊所有RD吧。
取消網頁所有的圖樣、特效、Framework、等等動態效果,只用最簡單的 html 開發。嗯!有效!但是老闆跟客戶不會買單。這麼陽春的頁面別說要賣幾萬塊,連要送人家用,人家還會質疑這是不是才剛寫好用來測試的。
自己寫一套瀏覽器。這是 bigcandy 大大看場面緊張,所以說說笑的。感謝 bigcandy 大大。
對動態網頁開發有經驗的邦友們,大概都能看出些蛛絲馬跡了。動態網頁通常只管 new 出物件來用,只管對 DOM 做 appendChild、innerHTML 來插入內容,只管用匿名函式 obj = function(){ ... }; 。但是做這些事前,不會考慮它們到底會不會被釋放,什麼時候被釋放。所以一再使用的情況下,記憶體就一點一點被佔光,直到瀏覽器再也要不到記憶體而宣告陣亡。
所以解決的方式如下:
一、在瀏覽器本身沒有 memory leak 的情況下
在此情況下,只有 DOM、Javascript 的 new 新物件、匿名函式會造成記憶體飆高。所以
a. DOM 不用了,必須設為 null 銷毀,而且要一層一層遞迴去做,從最底的 child 一路往上設為 null,才算完整把物件所佔用的記憶體都清除。
b. new 出來的新物件也是要設為 null,就算是 var 宣告的區域變數也一樣。
c. 別使用匿名函式。因為它只長不消。除非從頭到尾只有一個,而不是放在函式或迴圈中,不知道會生出幾個的情況。
d. 注意別交叉參考,不要讓 DOM 與 javascript new 出來的物件混淆,以免進行遞迴刪除時,瀏覽器直接死當。
e. 小心使用 Comet 與 Framework (如 Socket.IO、Ext-JS)。這些都有 memory leak 問題,長時間 pulling 會消耗掉大量記憶體,可以的話,用最原始的 xmlhttprequest 自己做 pulling。
二、在瀏覽器本身有 memory leak 的情況下
當然要先解決瀏覽器本身的 memory leak,假如官方已經有 patch,當然以 patch 為優先。敝人採用的瀏覽器是 IE8,它的 <img> 圖形有 memory leak 問題,用了就不釋放了。所以如果 javascript 程式中有頻繁去換 <img> 的 src="圖檔" 這種語法,或者用 innerHTML 頻繁更換圖形節點,那記憶體鐵定是一路飆高的。很遺憾到目前為止,微軟不打算修正。原因大概就是我所說的,太少人會遇到因為 <img> 不回收記憶體而出問題,因為在還沒出問題前,就已經換頁或關掉。就算 IE 當掉了,99.99% 的人也是重開了事吧,誰會向微軟回報?
關於 IE8 的 <img> 問題,網路上有人提出解法,使用 <span style="background-image: url(圖檔URL); width: 寬px; height: 高px"/> 來取代 <img src="圖檔URL" width="寬" height="高">。嗯!有效。
不過萬惡的 IE,每版有不同的 memory leak 問題。雖然 IE9 沒有 <img> 問題,但有其它問題,不過這不是在敝人這個需求內了。
~非常~非常~感激大師的指導
雖然我不是RD OR Coder,仍然覺得受用
請受小弟一拜~期待您的鐵人賽作品!!
感謝 bigcandy 大大的賞識。老實說,小弟看了這一兩年的鐵人賽,不是不想參加,只是工作時間關係,很難保證可以30天不間斷地每天產出技術文,太敷衍的又不想隨便就端出來丟人現眼,所以就沒硬著頭皮報名。
這種連續發表,講老實話,小弟也曾經瘋過 .... 連續寫一千篇情詩給女朋友,將近三年的時間,每天一篇肉麻兮兮、情話綿綿的情詩,比技術文還要命 ...
反正沒鐵人殊榮,不影響我分享啦!有一點研究還是會野人獻曝一下,希望大家不吝指教。
真的是高手,把原廠不處理的問題解套,有如神仙下凡啊~
好的記憶體管理,讓你上天堂 ; 不好的記憶體管理,讓你想上天堂~
zenlin
阿仁哥潛水偷看了兩年,今天才冒出來發言啊?
咱們開發了七、八年的 Web 系統,什麼鳥問題都遇過,就這個擺著長時間運作的問題沒解過。這次算是近兩年的傾力之作了。